package com.ruoyi.project.business.domain.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.project.business.dailyschedulerule.entity.DailyscheduleRule;
import com.ruoyi.project.business.domain.exceptions.RuleException;
import com.ruoyi.project.business.domain.rules.ForManagerRule;
import com.ruoyi.project.business.domain.rules.Rule;
import com.ruoyi.project.business.domain.rules.daily.ExpectedTime;
import com.ruoyi.project.business.domain.rules.daily.KeepForDailyRulePackage;
import com.ruoyi.project.business.domain.rules.month.KeepForMonthRulePackage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class RuleUtil {


    public static void sortRules(List<Rule> list) {
        Collections.sort(list, new Comparator<Rule>() {
            @Override
            public int compare(Rule o1, Rule o2) {
                if(o1.getOrder() == null || o2.getOrder() == null) {
                    throw new RuleException("规则冲突: 请设置冲突规则的优先级", -1);
                }
                return o1.getOrder().compareTo(o2.getOrder());
            }
        });

    }

    public static Rule getMaxRule(List<Rule> list) {
        sortRules(list);
        return list.get(list.size() -1);
    }

    public static List<Rule> getAbandonedRules(List<Rule> list) {
        sortRules(list);
        list.remove(list.size() -1);
        return list;
    }

    public static Rule initializeMonthRuleBean(String clazzName, Integer order, String breakTips, Boolean breakIfReject) {
        try {
            Class<? extends Rule> clazz = monthRuleMap.get(clazzName);
            if(clazz != null) {
                Rule rule = clazz.newInstance();
                rule.setOrder(order);
                rule.setBreakTips(breakTips);
                rule.setBreakIfReject(breakIfReject);
                rule.setConflicts();
                return rule;
            }
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuleException("系统初始化规则异常 " + clazzName);
        }
        throw new RuleException("未定义的规则 " + clazzName);
    }

    public static Rule initializeDailyRuleBean(String clazzName, Integer order, String breakTips, Boolean breakIfReject) {
        try {
            Class<? extends Rule> clazz = dailyRuleMap.get(clazzName);
            if(clazz != null) {
                Rule rule = clazz.newInstance();
                rule.setOrder(order);
                rule.setBreakTips(breakTips);
                rule.setBreakIfReject(breakIfReject);
                rule.setConflicts();
                return rule;
            }
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuleException("系统初始化规则异常 " + clazzName);
        }
        throw new RuleException("未定义的规则 " + clazzName);
    }

    public static List<String> findMonthRuleSimpleClassNames() {
        return monthRuleSubClassNames;
    }

    public static List<String> findMonthRuleSimpleClassNamesOfManager() {
        return monthRuleSubClassNamesOfManagerRule;
    }

    public static List<String> findDailyRuleSimpleClassNames() {
        return dailyRuleSubClassNames;
    }

    public static List<String> findDailyRuleSimpleClassNamesOfManager() {
        return dailyRuleSubClassNamesOfManagerRule;
    }

    private static List<Class> findRuleClasses(Class<Rule> superClass, String packageName) {
        Reflections reflections = new Reflections(packageName);
        Set<Class<? extends Rule>> subTypes = reflections.getSubTypesOf(superClass);
        List<Class> monthRuleSubClasses = new ArrayList<>(subTypes);
        return monthRuleSubClasses;
    }

    private static List<String> monthRuleSubClassNames;
    private static List<String> monthRuleSubClassNamesOfManagerRule;
    private static List<String> dailyRuleSubClassNames;
    private static List<String> dailyRuleSubClassNamesOfManagerRule;
    private static Map<String, Class<? extends Rule>> monthRuleMap;
    private static Map<String, Class<? extends Rule>> dailyRuleMap;

    public static String MONTH_RULE_PACKAGE = KeepForMonthRulePackage.class.getPackage().getName();
    public static String DAILY_RULE_PACKAGE = KeepForDailyRulePackage.class.getPackage().getName();

    static {
        List<Class> ruleClasses = findRuleClasses(Rule.class, MONTH_RULE_PACKAGE);
        monthRuleMap = ruleClasses.stream().collect(Collectors.toMap(single -> single.getSimpleName(), single -> single));
        // 未继承 ForManagerRule 的
        monthRuleSubClassNames = ruleClasses.stream()
                .filter(single -> !ForManagerRule.class.isAssignableFrom(single))
                .map(single -> single.getSimpleName()).collect(Collectors.toList());

        // 继承了 ForManagerRule 的
        monthRuleSubClassNamesOfManagerRule = ruleClasses.stream()
                .filter(single -> ForManagerRule.class.isAssignableFrom(single))
                .map(single -> single.getSimpleName()).collect(Collectors.toList());


        List<Class> dailyRuleClasses = findRuleClasses(Rule.class, DAILY_RULE_PACKAGE);
        dailyRuleMap = dailyRuleClasses.stream().collect(Collectors.toMap(single -> single.getSimpleName(), single -> single));

        // 未继承 ForManagerRule 的
        dailyRuleSubClassNames = dailyRuleClasses.stream()
                .filter(single -> !ForManagerRule.class.isAssignableFrom(single))
                .map(single -> single.getSimpleName()).collect(Collectors.toList());

        dailyRuleSubClassNamesOfManagerRule = dailyRuleClasses.stream()
                .filter(single -> ForManagerRule.class.isAssignableFrom(single))
                .map(single -> single.getSimpleName()).collect(Collectors.toList());
        // 继承了 ForManagerRule 的
    }

    public static Rule getRule(DailyscheduleRule rule) {
        String clazzName = rule.getBeanname();
        Integer order = 0; //  TODO 回头设计到页面上去
        String breakTips = "";
        Boolean breakIfReject = false; // TODO 回头设计到页面上去
        Rule tmp = RuleUtil.initializeDailyRuleBean(clazzName, order, breakTips, breakIfReject);

        if(StringUtils.equals(clazzName, ExpectedTime.class.getSimpleName())) {
            String beanparam = rule.getBeanparam();
            if(StringUtils.isNotBlank(beanparam)) {
                JSONObject jsonObject = JSON.parseObject(beanparam);
                String expectStartStr = jsonObject.getString("expectedTimeStart");
                LocalTime expectStart = LocalTime.parse(expectStartStr);
                String expectEndStr = jsonObject.getString("expectedTimeEnd");
                LocalTime expectEnd = LocalTime.parse(expectEndStr);

                ExpectedTime expectedTime = (ExpectedTime) tmp;
                expectedTime.setExpectStart(expectStart);
                expectedTime.setExpectEnd(expectEnd);
            }
        }
        tmp.setUserId(rule.getUserId());
        return tmp;
    }
}

